import service, { type RequestConfig } from '@/config/axios'
import { RequestMethod, ContentType } from '@/types/http'

/**
 * HTTP 请求工具类
 * 提供统一的 API 调用方法
 */
class HttpUtil {
  /**
   * 通用请求方法
   * @param config 请求配置
   * @returns Promise<T>
   */
  private async request<T = any>(config: RequestConfig): Promise<T> {
    try {
      const response = await service(config)
      return response.data.data || response.data
    } catch (error) {
      return Promise.reject(error)
    }
  }

  /**
   * GET 请求
   * @param url 请求地址
   * @param params 查询参数
   * @param config 额外配置
   * @returns Promise<T>
   */
  async get<T = any>(
    url: string,
    params?: any,
    config?: RequestConfig
  ): Promise<T> {
    return this.request<T>({
      method: RequestMethod.GET,
      url,
      params,
      ...config
    })
  }

  /**
   * POST 请求
   * @param url 请求地址
   * @param data 请求数据
   * @param config 额外配置
   * @returns Promise<T>
   */
  async post<T = any>(
    url: string,
    data?: any,
    config?: RequestConfig
  ): Promise<T> {
    return this.request<T>({
      method: RequestMethod.POST,
      url,
      data,
      ...config
    })
  }

  /**
   * POST 表单请求
   * @param url 请求地址
   * @param data 表单数据
   * @param config 额外配置
   * @returns Promise<T>
   */
  async postForm<T = any>(
    url: string,
    data?: any,
    config?: RequestConfig
  ): Promise<T> {
    return this.request<T>({
      method: RequestMethod.POST,
      url,
      data,
      headers: {
        'Content-Type': ContentType.FORM_URLENCODED
      },
      ...config
    })
  }

  /**
   * PUT 请求
   * @param url 请求地址
   * @param data 请求数据
   * @param config 额外配置
   * @returns Promise<T>
   */
  async put<T = any>(
    url: string,
    data?: any,
    config?: RequestConfig
  ): Promise<T> {
    return this.request<T>({
      method: RequestMethod.PUT,
      url,
      data,
      ...config
    })
  }

  /**
   * DELETE 请求
   * @param url 请求地址
   * @param params 查询参数
   * @param config 额外配置
   * @returns Promise<T>
   */
  async delete<T = any>(
    url: string,
    params?: any,
    config?: RequestConfig
  ): Promise<T> {
    return this.request<T>({
      method: RequestMethod.DELETE,
      url,
      params,
      ...config
    })
  }

  /**
   * PATCH 请求
   * @param url 请求地址
   * @param data 请求数据
   * @param config 额外配置
   * @returns Promise<T>
   */
  async patch<T = any>(
    url: string,
    data?: any,
    config?: RequestConfig
  ): Promise<T> {
    return this.request<T>({
      method: RequestMethod.PATCH,
      url,
      data,
      ...config
    })
  }

  /**
   * 文件上传
   * @param url 上传地址
   * @param file 文件对象
   * @param data 额外数据
   * @param config 额外配置
   * @returns Promise<T>
   */
  async upload<T = any>(
    url: string,
    file: File,
    data?: Record<string, any>,
    config?: RequestConfig
  ): Promise<T> {
    const formData = new FormData()
    formData.append('file', file)
    
    // 添加额外数据
    if (data) {
      Object.keys(data).forEach(key => {
        formData.append(key, data[key])
      })
    }

    return this.request<T>({
      method: RequestMethod.POST,
      url,
      data: formData,
      headers: {
        'Content-Type': ContentType.FORM_DATA
      },
      ...config
    })
  }

  /**
   * 批量上传文件
   * @param url 上传地址
   * @param files 文件数组
   * @param data 额外数据
   * @param config 额外配置
   * @returns Promise<T>
   */
  async uploadMultiple<T = any>(
    url: string,
    files: File[],
    data?: Record<string, any>,
    config?: RequestConfig
  ): Promise<T> {
    const formData = new FormData()
    
    files.forEach((file, index) => {
      formData.append(`files[${index}]`, file)
    })
    
    // 添加额外数据
    if (data) {
      Object.keys(data).forEach(key => {
        formData.append(key, data[key])
      })
    }

    return this.request<T>({
      method: RequestMethod.POST,
      url,
      data: formData,
      headers: {
        'Content-Type': ContentType.FORM_DATA
      },
      ...config
    })
  }

  /**
   * 下载文件
   * @param url 下载地址
   * @param params 查询参数
   * @param filename 文件名
   * @param config 额外配置
   */
  async download(
    url: string,
    params?: any,
    filename?: string,
    config?: RequestConfig
  ): Promise<void> {
    try {
      const response = await service({
        method: RequestMethod.GET,
        url,
        params,
        responseType: 'blob',
        ...config
      })

      // 创建下载链接
      const blob = new Blob([response.data])
      const downloadUrl = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.href = downloadUrl
      
      // 设置文件名
      if (filename) {
        link.download = filename
      } else {
        // 尝试从响应头中获取文件名
        const contentDisposition = response.headers['content-disposition']
        if (contentDisposition) {
          const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
          if (filenameMatch && filenameMatch[1]) {
            link.download = filenameMatch[1].replace(/['"]/g, '')
          }
        }
      }
      
      // 触发下载
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      
      // 清理 URL 对象
      window.URL.revokeObjectURL(downloadUrl)
    } catch (error) {
      console.error('文件下载失败:', error)
      throw error
    }
  }
}

// 创建实例并导出
const http = new HttpUtil()

export default http

// 兼容性导出，保持与现有代码的兼容性
export { http }

// 为了保持与现有 API 的兼容性，也可以直接导出方法
export const request = {
  get: <T = any>(config: { url: string; [key: string]: any }) => http.get<T>(config.url, config.params, config),
  post: <T = any>(config: { url: string; data?: any; [key: string]: any }) => http.post<T>(config.url, config.data, config),
  put: <T = any>(config: { url: string; data?: any; [key: string]: any }) => http.put<T>(config.url, config.data, config),
  delete: <T = any>(config: { url: string; [key: string]: any }) => http.delete<T>(config.url, config.params, config),
  patch: <T = any>(config: { url: string; data?: any; [key: string]: any }) => http.patch<T>(config.url, config.data, config)
}
